home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / popcli.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  11KB  |  496 lines

  1. /*
  2.  *    POP2 Client routines.  Originally authored by Mike Stockett
  3.  *      (WA7DYX).
  4.  *    Modified 12 May 1991 by Mark Edwards (WA6SMN) to use new timer
  5.  *    facilities in NOS0423.  Fixed type mismatches spotted by C++.
  6.  *    Modified 27 May 1990 by Allen Gwinn (N5CKP) for compatibility
  7.  *      with later releases (NOS0522).
  8.  *    Added into NOS by PA0GRI (and linted into "standard" C)
  9.  *
  10.  *    Some code culled from previous releases of SMTP.
  11.  *
  12.  *    Client routines for Simple Mail Transfer Protocol ala RFC821
  13.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  14.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  15.  *    Permission granted for non-commercial copying and use, provided
  16.  *      this notice is retained.
  17.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  18.  *      also rebuilt locking mechanism
  19.  *    Copyright 1987 1988 David Trulli, All Rights Reserved.
  20.  *    Permission granted for non-commercial copying and use, provided
  21.  *    this notice is retained.
  22.  *
  23.  * ATARI Version by David Nash - dnash@chaos.demon.co.uk
  24.  *
  25.  * __stdargs pop_send
  26.  */
  27.  
  28. /****************************************************************************
  29. *    $Id: popcli.c 1.2 93/07/16 11:48:51 ROOT_DOS Exp $
  30. *    08 May 93    1.2        GT    Fix warnings.                                    *
  31. ****************************************************************************/
  32.  
  33. #include <stdio.h>
  34. #include <fcntl.h>
  35. #include <time.h>
  36. #include <setjmp.h>
  37. #ifdef UNIX
  38. #include <sys/types.h>
  39. #endif
  40. #ifdef    __TURBOC__
  41. #include <dir.h>
  42. #include <io.h>
  43. #endif
  44. #include "global.h"
  45. #ifdef    ANSIPROTO
  46. #include <stdarg.h>
  47. #endif
  48. #include "mbuf.h"
  49. #include "cmdparse.h"
  50. #include "proc.h"
  51. #include "socket.h"
  52. #include "timer.h"
  53. #include "netuser.h"
  54. #include "dirutil.h"
  55. #include "files.h"
  56.  
  57. extern char Badhost[];
  58.  
  59. #define BUF_LEN        257
  60.  
  61. /* POP client control block */
  62.  
  63. struct pop_ccb {
  64.     int    socket;        /* socket for this connection */
  65.     char    state;        /* client state */
  66. #define       CALL        0
  67. #define       NMBR        3
  68. #define       SIZE        5
  69. #define       XFER        8
  70. #define       EXIT        10
  71.     char    buf[BUF_LEN],    /* tcp input buffer */
  72.         count;        /* input buffer length */
  73.     int    folder_len;    /* number of msgs in current folder */
  74.     long    msg_len;    /* length of current msg */
  75.     int    msg_num;    /* current message number */
  76. } *ccb;
  77.  
  78. #define NULLCCB        (struct pop_ccb *)0
  79.  
  80. static int Popquiet = 0;
  81.  
  82. static struct timer  popcli_t;
  83. static int32 mailhost;
  84. static char    mailbox_name[10],
  85.         mailbox_pathname[BUF_LEN],
  86.         username[20],
  87.         password[20],
  88.         Workfile_name[] ="mbox.pop";
  89.  
  90. static int domailbox __ARGS((int argc,char *argv[],void *p));
  91. static int domailhost __ARGS((int argc,char *argv[],void *p));
  92. static int douserdata __ARGS((int argc,char *argv[],void *p));
  93. static int doquiet __ARGS((int argc,char *argv[],void *p));
  94. static int dotimer __ARGS((int argc,char *argv[],void *p));
  95. static struct pop_ccb     *new_ccb __ARGS((void));
  96. static void delete_ccb __ARGS((void));
  97. static void __stdargs pop_send __ARGS((int unused,void *cb1,void *p));
  98. static int popkick __ARGS((int argc,char *argv[],void *p));
  99.  
  100. int  dopop(int, char*[], void *); 
  101. void pop_csm(struct pop_ccb *); 
  102. void quit_session(struct pop_ccb *); 
  103.  
  104. /* I don't know why this isn't static, it isn't called anywhere else {was} */
  105. int poptick __ARGS((void));
  106.  
  107. static struct cmds Popcmds[] = {
  108.     { "mailbox",    domailbox,    0,    0,    NULLCHAR },
  109.     { "mailhost",    domailhost,    0,    0,    NULLCHAR },
  110.     { "kick",        popkick,    0,    0,    NULLCHAR },
  111.     { "quiet",    doquiet,    0,    0,    NULLCHAR },
  112.     { "timer",    dotimer,    0,    0,    NULLCHAR },
  113.     { "userdata",    douserdata,    0,    0,    NULLCHAR },
  114.     { NULLCHAR },
  115. };
  116.  
  117.  
  118. /* Command string specifications */
  119.  
  120. static char ackd_cmd[] = "ACKD\n",
  121. #ifdef POP_FOLDERS
  122.     fold_cmd[] = "FOLD %s\n",
  123. #endif
  124.     login_cmd[] = "HELO %s %s\n",
  125.     /* nack_cmd[]      = "NACK\n",     /* Not implemented */
  126.     quit_cmd[]      = "QUIT\n",
  127.     read_cur_cmd[]  = "READ\n",
  128.     retr_cmd[]      = "RETR\n";
  129.  
  130. /* Response string keys */
  131.  
  132. static char *greeting_rsp  = "+ POP2 ";
  133.  
  134. FILE    *fd;
  135. #define    NULLFILE    (FILE *)0
  136.  
  137. int
  138. dopop(argc,argv,p)
  139. int     argc;
  140. char     *argv[];
  141. void     *p;
  142. {
  143.     return subcmd(Popcmds,argc,argv,p);
  144. }
  145.  
  146. static int
  147. domailbox(argc,argv,p) 
  148. int argc;
  149. char *argv[];
  150. void *p;
  151. {
  152.     if(argc < 2) {
  153.         if(mailbox_name[0] == '\0')
  154.             tprintf("maibox name not set yet\n");
  155.         else
  156.             tprintf("%s\n",mailbox_name);
  157.     } else {
  158.         strncpy(mailbox_name,argv[1],10);
  159.     }
  160.  
  161.     return 0;
  162. }
  163.  
  164. static int
  165. domailhost(argc,argv,p)
  166. int argc;
  167. char *argv[];
  168. void *p;
  169. {
  170.     int32 n;
  171.  
  172.     if(argc < 2) {
  173.         tprintf("%s\n",inet_ntoa(mailhost));
  174.     } else
  175.         if((n = resolve(argv[1])) == 0) {
  176.             tprintf(Badhost,argv[1]);
  177.             return 1;
  178.         } else
  179.             mailhost = n;
  180.  
  181.     return 0;
  182. }
  183.  
  184. static int
  185. doquiet(argc,argv,p)
  186. int argc;
  187. char *argv[];
  188. void *p;
  189. {
  190.     return setbool(&Popquiet,"POP quiet",argc,argv);
  191. }
  192.  
  193. static int
  194. douserdata(argc,argv,p)
  195. int argc;
  196. char *argv[];
  197. void *p;
  198. {
  199.     if (argc < 2)
  200.         tprintf("%s\n",username);
  201.     else if (argc != 3) {
  202.         tprintf("Usage: pop userdata <username> <password>\n");
  203.         return 1;
  204.     } else {
  205.         sscanf(argv[1],"%18s",username);
  206.         sscanf(argv[2],"%18s",password);
  207.     }
  208.  
  209.     return 0;
  210. }
  211.  
  212. /* Set scan interval */
  213.  
  214. static int
  215. dotimer(argc,argv,p)
  216. int argc;
  217. char *argv[];
  218. void *p;
  219. {
  220.     if(argc < 2) {
  221.         tprintf("%lu/%lu\n",
  222.             read_timer(&popcli_t) /1000L,
  223.             dur_timer(&popcli_t)/ 1000L);
  224.         return 0;
  225.     }
  226.  
  227.     popcli_t.func  = (void (*)())poptick;          /* what to call on timeout */
  228.     popcli_t.arg   = NULL;                /* dummy value */
  229.     set_timer(&popcli_t, atol(argv[1])*1000L);     /* set timer duration */
  230.     start_timer(&popcli_t);                /* and fire it up */
  231.     return 0;
  232. }
  233.  
  234. static int
  235. popkick(argc,argv,p)
  236. int argc;
  237. char *argv[];
  238. void *p;
  239. {
  240.     poptick();
  241.     return 0;
  242. }
  243.  
  244. int
  245. poptick()
  246. {
  247.     if (ccb == NULLCCB) {
  248.  
  249.         /* Don't start if any of the required parameters have not been specified */
  250.  
  251.         if (mailhost == 0) {
  252.             tprintf("mailhost not defined yet.(pop mailhost <host>)\n");
  253.             return 0;
  254.         }
  255.  
  256.         if (mailbox_name[0] == '\0') {
  257.             tprintf("mailbox name not defined yet.(pop mailbox <name>)\n");
  258.             return 0;
  259.         }
  260.  
  261.         if (username[0] == '\0') {
  262.             tprintf("username not defined yet. (pop user <name> <pass>)\n");
  263.             return 0;
  264.         }
  265.  
  266.         if (password[0] == '\0') {
  267.             tprintf(" Unknown password\n");
  268.             return 0;
  269.         }
  270.  
  271.         if ((ccb = new_ccb()) == NULLCCB) {
  272.             fprintf(stderr,"*** Unable to allocate CCB");
  273.             return 0;
  274.         }
  275.  
  276.         newproc("Auto-POP Client",1024,pop_send,0,ccb,NULL,0);
  277.     }
  278.  
  279.     /* Restart timer */
  280.  
  281.     start_timer(&popcli_t);
  282.     return 0;
  283. }
  284.  
  285. /* this is the master state machine that handles a single SMTP transaction */
  286. /* it is called with a queue of jobs for a particular host. */
  287.  
  288. static void
  289. __stdargs pop_send(unused,cb1,p) 
  290. int unused;
  291. void *cb1;
  292. void *p;
  293. {
  294.     char *cp;
  295.     struct sockaddr_in fsocket;
  296.     struct pop_ccb    *ccb;
  297. #ifndef ATARI
  298.     void pop_csm(struct pop_ccb *);
  299. /*    void quit_session(struct pop_ccb *); */
  300. #endif
  301.  
  302.     ccb = (struct pop_ccb *)cb1;
  303.     fsocket.sin_family = AF_INET;
  304.     fsocket.sin_addr.s_addr = mailhost;
  305.     fsocket.sin_port = IPPORT_POP;
  306.  
  307.     ccb->socket = socket(AF_INET,SOCK_STREAM,0);
  308.  
  309.     ccb->state = CALL;
  310.  
  311.     if (connect(ccb->socket,(char *)&fsocket,SOCKSIZE) == 0) {
  312.         log(ccb->socket,"Connected to mailhost %s", inet_ntoa(mailhost));
  313.     } else {
  314.         cp = sockerr(ccb->socket);
  315.         log(ccb->socket,"Connect to mailhost %s failed: %s", inet_ntoa(mailhost),
  316.             (cp != NULLCHAR)? cp: "");
  317.     }
  318.  
  319.     while(1) {
  320.         if (recvline(ccb->socket,ccb->buf,BUF_LEN) == -1)
  321.             goto quit;
  322.  
  323.         rip(ccb->buf);
  324.         pop_csm(ccb);
  325.         if (ccb->state == EXIT)
  326.             goto quit;
  327.     }
  328. quit:
  329.     log(ccb->socket,"Connection closed to mailhost %s", inet_ntoa(mailhost));
  330.     (void) close_s(ccb->socket);
  331.     if (fd != NULLFILE)
  332.         fclose(fd);
  333.     delete_ccb();
  334. }
  335.  
  336. /* free the message struct and data */
  337.  
  338. static void
  339. delete_ccb()
  340. {
  341.     if (ccb == NULLCCB)
  342.         return;
  343.  
  344.     free((char *)ccb);
  345.     ccb = NULLCCB;
  346. }
  347.  
  348. /* create a new  pop control block */
  349.  
  350. static struct
  351. pop_ccb *new_ccb()
  352. {
  353.     register struct pop_ccb *ccb;
  354.  
  355.     if ((ccb = (struct pop_ccb *) callocw(1,sizeof(struct pop_ccb))) == NULLCCB)
  356.         return(NULLCCB);
  357.     return(ccb);
  358. }
  359.  
  360. /* ---------------------- pop client code starts here --------------------- */
  361.  
  362. void
  363. pop_csm(ccb)
  364. struct pop_ccb    *ccb;
  365. {
  366.     FILE *mf;
  367.  
  368.     int mlock (char *,char *);
  369.     int rmlock (char * ,char *);
  370. #ifndef ATARI    
  371.     void quit_session(struct pop_ccb *);
  372.     /* int mlock __ARGS((char *dir,char *id));   */
  373.     /* int rmlock __ARGS((char *dir,char *id));   */
  374. #endif
  375.  
  376.     switch(ccb->state) {
  377.     case CALL:
  378.         if (strncmp(ccb->buf,greeting_rsp,strlen(greeting_rsp)) == 0) {
  379.              (void)usprintf(ccb->socket,login_cmd,username,password);
  380.             ccb->state = NMBR;
  381.         } else
  382.             (void) quit_session(ccb);
  383.         break;
  384.  
  385.     case NMBR:
  386.  
  387.         switch (ccb->buf[0]) {
  388.         case '#':
  389.             if ((fd = fopen(Workfile_name,"a+")) == NULLFILE) {
  390.                 perror("Unable to open work file");
  391.                 quit_session(ccb);
  392.                 return;
  393.             }
  394.  
  395.             fseek(fd,0,SEEK_SET);
  396.             ccb->folder_len = atoi(&(ccb->buf[1]));
  397.             (void)usprintf(ccb->socket,read_cur_cmd);
  398.             ccb->state = SIZE;
  399.             break;
  400.  
  401.         case '+':
  402.  
  403.             /* If there is no mail (the only time we get a "+"
  404.              * response back at this stage of the game),
  405.              * then just close out the connection, because
  406.              * there is nothing more to do!! */
  407.  
  408.         default:
  409.             quit_session(ccb);
  410.             break;
  411.         }
  412.     break;
  413.  
  414.     case SIZE:
  415.         if (ccb->buf[0] == '=') {
  416.             ccb->msg_len = atol(&(ccb->buf[1]));
  417.             if (ccb->msg_len > 0) {
  418.                 (void)usprintf(ccb->socket,retr_cmd);
  419.  
  420.                 ccb->state = XFER;
  421.             } else {
  422.                 log(ccb->socket,"POP client retrieved %d messages",
  423.                         ccb->folder_len);
  424.  
  425.                 /* All done, so do local cleanup */
  426.  
  427.                 if (mlock(Mailspool,mailbox_name)) {
  428.                     tprintf("\n*** Local mailbox locked, new mail in file %s\n",
  429.                          Workfile_name);
  430.                     quit_session(ccb);
  431.                     return;
  432.                 }
  433.  
  434.                 sprintf(mailbox_pathname,"%s/%s.txt",Mailspool,
  435.                     mailbox_name);
  436.                 if ((mf = fopen(mailbox_pathname,"a+")) == NULL) {
  437.                     tprintf("\n*** Unable to open local mailbox, new mail in file %s\n",
  438.                            Workfile_name);
  439.                     quit_session(ccb);
  440.                     return;
  441.                 }
  442.  
  443.                 fseek(fd,0,SEEK_SET);
  444.  
  445.                 while (!feof(fd)) {
  446.                     if(fgets(ccb->buf,BUF_LEN,fd) != NULLCHAR) {
  447.                         fputs(ccb->buf,mf);
  448.                     }
  449.                 }
  450.                 fclose(mf);
  451.                 fclose(fd);
  452.                 fd = NULL;
  453.                 tprintf("New mail arrived for %s from mailhost <%s>%c\n",
  454.                     mailbox_name, inet_ntoa(mailhost),
  455.                     Popquiet ? ' ' : '\007');
  456.                 rmlock(Mailspool,mailbox_name);
  457.                 unlink(Workfile_name);
  458.                 quit_session(ccb);
  459.             }
  460.         } else
  461.             quit_session(ccb);
  462.         break;
  463.  
  464.         case XFER:
  465.             fprintf(fd,"%s\n",ccb->buf);
  466.  
  467.             ccb->msg_len -= (long)(strlen(ccb->buf)+2);    /* Add CRLF */
  468.  
  469.             if (ccb->msg_len > 0)
  470.                 return;
  471.  
  472.             (void)usprintf(ccb->socket,ackd_cmd);
  473.  
  474.             ccb->msg_num++;
  475.             ccb->state = SIZE;
  476.             break;
  477.  
  478.         case EXIT:
  479.             if (fd != NULLFILE)
  480.                 fclose(fd);
  481.             break;
  482.  
  483.         default:
  484.             break;
  485.     }
  486. }
  487.  
  488. void
  489. quit_session(ccb)
  490. struct pop_ccb    *ccb;
  491. {
  492.     (void)usprintf(ccb->socket,quit_cmd);
  493.  
  494.     ccb->state  = EXIT;
  495. }
  496.